package com.wutong.engine.anything;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.wutong.engine.exception.MkdirException;
import org.slf4j.Logger;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * JSON配置文件的加载和保存，提供配置的保存和获取功能，其中T为需要保存配置文件的类对象类型
 *
 * @author 王益凡
 */
public class Config<T> {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final Logger log = GameLogger.getLogger(Config.class);

    private final Class<T> clazz;

    private static final String CONFIG_PATH = System.getProperty("user.dir") + "\\config\\";
    private static final File CONFIG_FILE = new File(CONFIG_PATH);

    private final String fileName;
    private final File file;

    static {
        // 创建config目录
        if (!CONFIG_FILE.exists()) {
            log.info("config目录不存在，创建config目录");
            if (CONFIG_FILE.mkdirs()) {

                log.info("创建config目录成功");
            } else {
                log.error("创建config目录失败");
                throw new MkdirException("创建config目录失败");
            }
        }
        // 添加Json设置格式
        OBJECT_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
    }

    /**
     * 构造函数
     *
     * @param fileName 文件名，无需后缀名，为json
     * @param clazz    类class字节码
     */
    public Config(String fileName, Class<T> clazz) {
        this.fileName = fileName + ".json";
        this.clazz = clazz;
        this.file = new File(CONFIG_PATH + this.fileName);
        try {
            if (!file.exists()) {
                log.warn("当前 {} 配置文件并不存在，将进行自动创建", this.fileName);
                if (file.createNewFile()) {
                    log.info("创建 {} 配置文件完成", this.fileName);
                } else {
                    log.warn("创建 {} 配置文件失败，请手动检查", this.fileName);
                }
            } else {
                log.info("已检索到指定 {} 配置文件，已成功加载", this.fileName);
            }
        } catch (IOException e) {

            log.warn("创建文件失败，请检查 -> {}: {}", e.getClass().getSimpleName(), e.getMessage());
        }
    }

    /**
     * 加载配置文件
     *
     * @return T
     */
    public T loadConfig() {
        try {
            if (!file.exists()) {
                log.error("所需配置文件 {} 并不存在，请检查", CONFIG_PATH + fileName);
                throw new MkdirException("所需配置文件 %s 并不存在，请检查".formatted(CONFIG_PATH + fileName));
            }
            return OBJECT_MAPPER.readValue(file, clazz);
        } catch (IOException e) {
            log.warn("读取配置文件失败，请联系作者: {} -> {}", e.getClass().getSimpleName(), e.getMessage());
            return null;
        }
    }

    /**
     * 保存配置文件
     *
     * @param configData 需要保存的配置类
     *
     * @return 是否保存成功
     */
    public boolean saveConfig(T configData) {
        try {
            if (!file.exists()) {
                log.warn("{} 配置文件不存在，正在重新创建", fileName);
                if (file.createNewFile()) {
                    log.info("文件创建成功，写入 {} 配置文件", fileName);
                } else {
                    log.error("文件创建失败，保存 {} 配置文件失败，请检查", fileName);
                }
            } else {
                log.info("配置文件存在，保存到 {} 配置文件", fileName);
            }
            OBJECT_MAPPER.writeValue(file, configData);
            return true;
        } catch (IOException e) {
            log.warn("配置文件读写失败，请检查是否文件时候被占用使用 {} -> {}", e.getClass().getSimpleName(), e.getMessage());
            return false;
        }
    }

    public String getFileName() {
        return fileName;
    }

    public File getFile() {
        return file;
    }

    public static boolean saveJsonByMap(String fileName, Map<String, Object> map) {
        fileName += ".json";
        File file = new File(CONFIG_PATH + fileName);
        try {
            if (!file.exists()) {
                log.warn("未检索到 {} 配置文件，将自动创建", fileName + ".json");
                if (file.createNewFile()) {
                    log.info("创建 {} 配置文件成功，写入保存", fileName);
                } else {
                    log.error("创建 {} 配置文件失败，请检查", fileName);
                    return false;
                }
            }
            OBJECT_MAPPER.writeValue(file, map);
            log.info("写入 {} 配置文件完成", fileName);
            return true;
        } catch (IOException e) {
            log.error("写入 {} 配置文件失败，请检查", fileName);
            return false;
        }
    }

    public static Map<String, Object> loadJsonToMap(String fileName) {
        fileName += ".json";
        File file = new File(CONFIG_PATH + fileName);
        if (!file.exists()) {
            log.error("未找到 {} 配置文件，取消读取", fileName);
            return new HashMap<>();
        }
        log.info("已检索到 {} 配置文件，加载配置文件", fileName);
        try {
            return OBJECT_MAPPER.readValue(file, new TypeReference<>() {
            });
        } catch (IOException e) {
            log.error("无法正常读取 {} 配置文件，请检查", fileName);
            return new HashMap<>();
        }
    }
}
